This Technical Note explains how the Apple Desktop Bus (ADB) works on the Macintosh. This Note covers the boot process, driver installation, use of ADB Manager calls, and answers commonly asked questions.
Changes since August 1989: Added an additional vendor for ADB cables.
During the boot process, the ADB Manager finds all the devices on the bus and resolves any address conflicts. An address conflict is defined as two or more devices with the same original (default) address. A good example of this conflict is a mouse and a graphics tablet that are both at address 3 (relative device). The ADB Manager resolves these address conflicts as described in Appendix B of the ADB Specification (Apple Drawing #062-0267-E) and the Q & A section of this document.
After the address resolution, the devices which have been ΓÇ£movedΓÇ¥ due to address conflicts are now addressed, starting from the highest unused soft address and working down. The system now loads and executes all the resources of type 'ADBS' that match the devices on the bus (by original address).
Once all the ADB service routines are installed, the ADB transceiver
(microcontroller) chip starts polling the active device. The active device is defined as the last device to send data. Since the mouse (pointing device) is the most likely device to have data ready at any given time, it defaults as the active device after startup.
The transceiver polls the active device (approximately every 11 milliseconds), with a Talk R0 command. If the active device has new data, it can respond with it, and if it does not, it just times out. If any other devices have data to send, they can assert SRQ (refer to Figure 5 of the ADB Specification) at the end of the talk R0 command. When the host detects an SRQ, it begins polling all addresses with a talk R0 command until one returns data. That device then becomes the active device.
Devices have no way of knowing if they are the ΓÇ£active deviceΓÇ¥. The algorithm for a device with data ready to send is as follows:
ΓÇó Wait for a talk R0 command (this happens every 10 milliseconds).
ΓÇó If the Talk R0 is for you, then return the data.
ΓÇó If the Talk R0 is not for you, wait for the end of the command,
and assert SRQ.
ΓÇó If the Talk R0 is addressed to you, then respond with your data.
Now that a device has been polled, the host retrieves the data from the bus and calls the service routine installed for that device (service routines are installed by calling _SetADBInfo and are maintained by the ADB Manager). The system passes pointers to the service routine itself, its data area, and the data received from the device, as well as the ADB command byte that caused the routine to be called.
Normally, the service routine does not need to use the _ADBOp call to retrieve data. The ADB ΓÇ£philosophyΓÇ¥ assumes that register zero of a device is the main data transmission register. Since register zero is automatically polled by the system, there should be no need to call _ADBOp from the service routine. Typically, _ADBOp is used to set modes of a device, or to interrogate the device for statusΓÇöthe sort of things that should not need to be done more than once or twice during normal operation.
It is important to note that ADB service routines are called at interrupt time, which means that they must follow all the rules regarding code that executes at interrupt time. (See Inside Macintosh references to VBL tasks and Device Manager I/O completion routines.)
Installing an ADB Service Routine and Optional Data Area
ΓÇó Using the 'ADBS' resource mechanism. At boot time the system searches
for 'ADBS' resources in the System file. The system matches desktop
bus devices by their original address to an 'ADBS' resource (i.e., if
the machine has a device that responds at address 4, the system looks
for an 'ADBS' resource with ID=4). When the system finds these resources,
it loads and executes them. The limitation of this method is that there
can only be one 'ADBS' resource for each address on the bus.
A typical 'ADBS' resource allocates space in the system heap for its
service routine and, optional, data area. Next, it moves the service
routine into the allocated space and initializes the data area, if
necessary. This code should also install an _ADBReInit preprocessing
routine to deallocate the memory used by the service routine (Inside
Macintosh V-367).
When the system loads and executes an 'ADBS' resource, it passes the
following parameters:
A0 = Address of 'ADBS' resource in memory.
D0 = ADB device address (0-15). This address may be different than
the ΓÇ£original address,ΓÇ¥ since it occurs after address resolution.
D1 = ADB Device Type (same as the handler ID)
With this information, the 'ADBS' code can call _SetADBInfo to install
the service routine and data area. The installer should make sure the
handler ID (Device Type) is the one it expects.
ΓÇó Install the service routine and data area using an 'INIT' resource.
This method works the same as an 'ADBS' resource, except you are not
passed the parameters in A0, D0, and D1, so you at least need to
interrogate the ADB Manager (using _GetIndADB) to get the information.
Remember to lock yourself down.
ΓÇó Use the 'INIT' resource method from within an application.
Answers to Commonly-Asked ADB Questions
Question: I need information on developing an Apple Desktop Bus product.
Answer: AppleΓÇÖs Desktop Bus and ADB Device Specifications are a licensable
product available through Software Licensing. For more information,
contact:
Apple Software Licensing
Apple Computer, Inc.,
20525 Mariani Avenue, M/S 38-I
Cupertino, CA, 95014
(408) 974-4667
AppleLink: SW.LICENSE
Additional ADB references are as follows:
Macintosh
Inside Macintosh, Volume V, The Apple Desktop Bus
Macintosh Family Hardware Reference
Apple II
Apple IIgs Hardware Reference Manual
Desktop Bus
Apple IIgs Firmware Reference Manual
General
Baum, Peter. ΓÇ£Boarding the Bus,ΓÇ¥ MacUser, July 1987, p. 142.
ΓÇ£An Overview of Apple Desktop Bus,ΓÇ¥
Call A.P.P.L.E., June 1987, p. 24.
Question: I would like to extend the keyboard cable for my Macintosh.
How can I do this, and how can I make the extension?
Answer: The ADB specification states the maximum length of all cables
on the Desktop Bus is five meters. If you wish to use longer
cables than those supplied with the ADB device, Kensington
MicroWare (800) 535-4242, Monster Cable (800) 331-3755, and
Data Spec (800) 431-8124 all supply them.
Disclaimer: This listing for Kensington MicroWare, Monster
Cable, and Data Spec neither implies nor constitutes
an endorsement by Apple Computer, Inc. If your
company supplies these cables and you would like
to be listed, contact us at the address in Technical
Note #0.
Question: How can I use the LEDs on the Apple Extended Keyboard?
Answer: Using the LEDs on the extended keyboard involves the _ADBOp
call. Once you determine that you have an extended keyboard
(with _CountADBs and _GetIndADB), then register 2 of the extended
keyboard has the LED toggles in the low 3 bits.
Therefore, you would do a Talk to register 2 to have the device
send you the contents of register 2, manipulate the low three
bits to set the LEDs, and then pass the modified register 2 back
to the device with a Listen to register 2 command.
The Apple Extended Keyboard has an ID of 02 and a device handler
ID of 02, while the Apple Standard Keyboard has an ID of 02 and
a device handler ID of 01.
Note: At this point it is not clear what Apple has in mind for
these LEDs, so you are using them at your own risk.
Question: I am confused about the service routines and data areas passed
in the _ADBOp call. What does it all mean?
Answer: That ΓÇÖs a good question.
FUNCTION ADBOp (data:Ptr; compRout:ProcPtr; buffer:Ptr;
commandNum:INTEGER) : oserr;
data is a pointer to the ΓÇ£optional data areaΓÇ¥. This
area is provided for the use of the service routine
(if needed).
compRout is a pointer to the completion or service routine
to be called when the _ADBOp command has been
completed. It has the same meaning as the service
routine passed to the _SetADBInfo call.
buffer is a pointer to a Pascal string, which may contain
zero to eight bytes of information. These are the
two to eight bytes that a particular register of an
ADB device is capable of sending and receiving.
commandNum is an integer that describes the command to be
sent over the bus.
There is some confusion over the way that the completion routines
are called from _ADBOp. This calling may be done in one of the
following three ways:
ΓÇó You do not wish to have a completion routine called, as in
a Listen command. Pass a NIL pointer to _ADBOp.
ΓÇó You wish to call the routine already in use by the system
for that address (as installed by _SetADBInfo). Call
_GetADBInfo before calling _ADBOp, and pass the routine
pointer returned by _GetADBInfo to _ADBOp.
ΓÇó You wish to provide your own completion routine and data
area for the _ADBOp call. In this case, simply pass your
own pointers to the _ADBOp call.
Remember, there should rarely be a reason to call _ADBOp. Most
cases are handled by the systemΓÇÖs polling and service request
mechanism. In the cases where it is necessary to call _ADBOp,
it should not be done in a polling fashion, but as a mechanism
of telling the device something (i.e., change modes, or in the
case of our extended keyboard, turn on or off an LED).
Question: How can I make my Macintosh II or IIx power up automatically
after a power outage?
Answer: The Macintosh II and IIx power can be turned on via the keyboard
through the Apple Desktop Bus port (ADB) since the reset key is
wired to pin two of the ADB connector. When you press this key,
it pulls pin two to ground and initiates a power-on sequence.
You can emulate this feature with a momentary switch connected
to the ADB port. Note that the switch on the back panel of a
Macintosh IIcx can be locked in the On position to automatically
restart after a power outage
An idea for a power-on circuit would be to have a momentary
(one-shot) relay powered by the same outlet that powers the
machine and have the contacts close pin two of the ADB connector.
(Without having tried this, I am concerned that you may need a
delay before the relay fires to give the AC time to stabilize, etc.)
Question: IΓÇÖm more than a little confused about the way ADB device address
conflicts are resolved at boot time. Can you enlighten me with
your infinite wisdom, Cameron?
Answer: The method used by the host to separate and identify the devices
at boot time is not well documented, so IΓÇÖll try to describe it
with some clarity.
The host issues a Talk R3 command to an address. LetΓÇÖs say there
are two devices at that address. Both try to respond to the
command, and when they try to put the random number (the address
field of register 3) on the bus, one of them should detect a
collision. The one that detects the collision backs off and marks
itself (internally) as unmovable.
The device that did respond successfully is then told to move to
a new address (the highest free address). By definition, moving
to a new address means that it now responds only to commands
addressed to this new address, and it ignores commands to the
original address.
The host then issues another Talk R3 command to the original
address. This time the second device responds without detecting
a collision. When it successfully completes a Talk R3 response,
it marks itself as movable. It then is told to move to a new
address.
The host again issues a Talk R3 command to the original address.
Since there are no more devices at that address, the bus times
out, and the host moves the last device back to the original address.
At this point, the host moves up to the next address that has a
device and begins the process all over.
Generally, when having trouble separating devices on the ADB, it
is because the collision detection doesnΓÇÖt work well. In fact,
this problem is evident on Apple keyboards. The bug is that the
random number returned in R3 isnΓÇÖt really a random number. Since
the microcontrollers on the keyboards are clocked with a crystal,
they tend to generate the same ΓÇ£randomΓÇ¥ number, so when the system
attempts to separate them with a Talk R3 command, they never detect
the collision.
One possible solution is to use a low-tolerance capacitor on the
reset line of the microcontroller, thereby forcing the time from
power on to the time reset is negated to be fairly random. In this
way, the microcontroller can start a count until it receives the
first Talk R3 command, and hopefully it is a different number than
another device at the same address on the bus.
If you find your device shows up at all addresses, it may be
because it is responding to the move address command when it should
be marked as unmovable.
Finally, if the device doesnΓÇÖt show up at all, it may be because
it is unable to respond to the Talk R3 command at boot time
(i.e., not able to initialize itself and start watching the bus